package com.bikes.mileagetracker

import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Color
import android.graphics.Point
import android.location.Location
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import android.view.View
import com.bikes.mileagetracker.MileageTrackerApplication.Companion.MAP_DEFAULT_ZOON_LEVEL
import com.bikes.mileagetracker.MileageTrackerApplication.Companion.MAP_MAX_ZOON_LEVEL
import com.bikes.mileagetracker.MileageTrackerApplication.Companion.MAP_MIN_ZOON_LEVEL
import com.bikes.mileagetracker.entity.LocationEntity
import com.bikes.mileagetracker.service.LocationService
import com.bikes.mileagetracker.service.PersistenceService
import com.bikes.mileagetracker.utils.TaskUtils
import com.bikes.mileagetracker.utils.whenOptionMapCenterFollowingRun
import com.google.android.gms.maps.*
import com.google.android.gms.maps.model.*
import org.apache.commons.lang3.StringUtils


class MapsActivity : AppCompatActivity(), OnMapReadyCallback, LocationSource {


    private lateinit var mMap: GoogleMap

    private lateinit var view: View

    private var mapLocationNotifier: LocationSource.OnLocationChangedListener? = null


    private val oldLocations = mutableListOf<LocationEntity>()
    private val currentLocations = mutableListOf<LocationEntity>()

    private val oldCircleMap = mutableMapOf<LocationEntity, Circle>()
    private val newCircleMap = mutableMapOf<LocationEntity, Circle>()
    private val newCircleReverseMap = mutableMapOf<Circle, LocationEntity>()


    var userLoc: Circle? = null
    override fun onOptionsItemSelected(item: MenuItem?): Boolean {
        // TODO Auto-generated method stub
        if(item!!.getItemId() == android.R.id.home)
        {
            finish();
            return true;
        }
        return super.onOptionsItemSelected(item)
    }


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_maps)
// Register Back button
        val actionBar = supportActionBar
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true)
            actionBar.setHomeButtonEnabled(true)
        }

        val locationServiceIntent = Intent(this.application, LocationService::class.java)

        initMap()

    }

    override fun onResume() {
        Log.v("console", "resume!!!!")
        super.onResume()
        initMap()


    }

    fun initMap() {


        oldLocations.clear()
        oldCircleMap.clear()

        TaskUtils.runInBackground {
            val ct = MileageTrackerApplication.getCurrentTracking()
            PersistenceService.service?.loadUserLocations(MileageTrackerApplication.getCurrentAccount()!!.id)?.forEach {

                if (StringUtils.equals(it.trackingId, ct?.id ?: null)) {
                    currentLocations.add(it)
                } else {
                    oldLocations.add(it)
                }
            }
        }

        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        val mapFragment = supportFragmentManager
                .findFragmentById(R.id.map) as SupportMapFragment


        mapFragment.getMapAsync(this)
        view = mapFragment.view!!

    }


    /**
     * Manipulates the map once available.
     * This callback is triggered when the map is ready to be used.
     * This is where we can add markers or lines, add listeners or move the camera. In this case,
     * we just add a marker near Sydney, Australia.
     * If Google Play services is not installed on the device, the user will be prompted to install
     * it inside the SupportMapFragment. This method will only be triggered once the user has
     * installed Google Play services and returned to the app.
     */
    @SuppressLint("MissingPermission")
    override fun onMapReady(googleMap: GoogleMap) {
        mMap = googleMap

        mMap.isMyLocationEnabled = true
        mMap.uiSettings.apply {
            isZoomControlsEnabled = false
            isZoomGesturesEnabled = true
            isScrollGesturesEnabled = true
            isCompassEnabled = true
            isMyLocationButtonEnabled = true
        }

        mMap.setMinZoomPreference(MAP_MIN_ZOON_LEVEL)
        mMap.setMaxZoomPreference(MAP_MAX_ZOON_LEVEL)
        mMap.moveCamera(CameraUpdateFactory.zoomBy(MAP_DEFAULT_ZOON_LEVEL))

        LocationService.LOCATION_UPDATE_DELEGATES.add(this::onMove)
        LocationService.LOCATION_ENTITY_CREATE_DELEGATES.add(this::onNewLocation)

        mMap.setLocationSource(this)

        currentLocations.forEach {
            onNewLocation(it)
        }

        mMap.setOnCircleClickListener { circle ->
            if (newCircleReverseMap.containsKey(circle)) {
                val entity = newCircleReverseMap[circle]
                if (entity != null) {
                    var lt = entity.locType ?: 0
                    lt = (lt + 1) % 4
                    entity.locType = lt
                    onNewLocation(entity)
                }
            }
        }

    }

    fun optionKalmanRemovedCircle(latlng: LatLng): CircleOptions {
        return CircleOptions().center(latlng)
                .fillColor(Color.rgb(12, 12, 12))
                .radius(5.0)
                .strokeWidth(0.0f)
                .clickable(true)
    }

    fun optionInaccurateCircle(latlng: LatLng): CircleOptions {
        return CircleOptions().center(latlng)
                .fillColor(Color.rgb(254, 245, 13))
                .radius(5.0)
                .strokeWidth(0.0f)
                .clickable(true)
    }


    fun optionNoAccuracyCircle(latlng: LatLng): CircleOptions {
        return CircleOptions().center(latlng)
                .fillColor(Color.rgb(254, 254, 254))
                .radius(5.0)
                .strokeWidth(0.0f)
                .clickable(true)
    }

    fun optionUserLocation(latlng: LatLng): CircleOptions {
        return CircleOptions().center(latlng)
                .fillColor(Color.rgb(255, 35, 12))
                .radius(5.0)
                .strokeWidth(0.0f)
                .clickable(true)
    }


    fun optionOldCircle(latlng: LatLng): CircleOptions {
        return CircleOptions().center(latlng)
                .fillColor(Color.rgb(152, 152, 152))
                .radius(5.0)
                .strokeWidth(0.0f)
    }

    fun optionMyLocation(latlng: LatLng): CircleOptions {
        return CircleOptions().center(latlng)
                .fillColor(Color.rgb(255, 35, 12))
                .radius(5.0)
                .strokeColor(Color.argb(50, 152, 152, 152))
                .strokeWidth(50.0f)
    }

    fun onNewLocation(entity: LocationEntity) {

        if (newCircleMap.containsKey(entity)) {
            newCircleMap[entity]?.remove()
        }

        val curc =
                when (entity.locType) {
                    3 -> mMap.addCircle(optionKalmanRemovedCircle(LatLng(entity.latitude, entity.longitude)))
                    2 -> mMap.addCircle(optionInaccurateCircle(LatLng(entity.latitude, entity.longitude)))
                    1 -> mMap.addCircle(optionNoAccuracyCircle(LatLng(entity.latitude, entity.longitude)))
                    else -> mMap.addCircle(optionUserLocation(LatLng(entity.latitude, entity.longitude)))
                }

        newCircleMap[entity] = curc
        newCircleReverseMap[curc] = entity

    }

    fun onMove(old: Location?, cur: Location) {

        var clatlng = LatLng(cur.latitude, cur.longitude)
        whenOptionMapCenterFollowingRun {
            val currentLocation = clatlng
            mMap.moveCamera(CameraUpdateFactory.newLatLng(currentLocation))
        }

        if (userLoc == null) {
            userLoc = mMap.addCircle(optionMyLocation(clatlng))
        }

        userLoc?.center = clatlng
        mapLocationNotifier?.onLocationChanged(cur)

        refreshOldMapOnMap()

    }

    override fun deactivate() {
        mapLocationNotifier = null
    }

    override fun activate(p0: LocationSource.OnLocationChangedListener?) {
        mapLocationNotifier = p0
    }

    fun refreshOldMapOnMap() {

        var minLat = Double.MAX_VALUE
        var maxLat = Double.MIN_VALUE
        var minLon = Double.MAX_VALUE
        var maxLon = Double.MIN_VALUE

        val border = listOf(

                mMap.projection.fromScreenLocation(Point(0, 0)),
                mMap.projection.fromScreenLocation(Point(0, view.height)),
                mMap.projection.fromScreenLocation(Point(view.width, 0)),
                mMap.projection.fromScreenLocation(Point(view.width, view.height)))

        for (cur in border) {
            if (cur.latitude < minLat) {
                minLat = cur.latitude
            }
            if (cur.latitude > maxLat) {
                maxLat = cur.latitude
            }
            if (cur.longitude < minLon) {
                minLon = cur.longitude
            }
            if (cur.longitude > maxLon) {
                maxLon = cur.longitude
            }
        }

        for (oldloc in oldLocations) {

            val lat = oldloc.latitude
            val lng = oldloc.longitude

            if (oldCircleMap.containsKey(oldloc)) {
                if (!(lat in minLat..maxLat && lng in minLon .. maxLon)) {
                    oldCircleMap[oldloc]?.remove()
                }
            } else {
                if (lat in minLat..maxLat && lng in minLon .. maxLon) {
                    oldCircleMap.put(oldloc, mMap.addCircle(optionOldCircle(LatLng(oldloc.latitude, oldloc.longitude))))
                }
            }

        }
    }

}
